SlideShare a Scribd company logo
1 of 148
Download to read offline
The Symfony Components – Fabien Potencier
Serial entrepreneur
Developer by passion
Founder of Sensio
Creator and lead developer of Symfony
On Twitter @fabpot
On github http://www.github.com/fabpot

            http://fabien.potencier.org/
             The Symfony Components – Fabien Potencier
Standalone components for PHP 5.3

       No dependency between them

Used extensively in Symfony 2, the framework

              The Symfony Components – Fabien Potencier
Low-level libraries
needed by most websites

      The Symfony Components – Fabien Potencier
Event Dispatcher                                              Stable

Output Escaper                                                Stable
                                                                       Extracted from symfony 1
YAML                                                          Stable

Routing                                                       Beta

Console                                                       Stable
Dependency Injection Container                                Stable   Written from scratch
                                                                       for Symfony 2
Request Handler                                               Stable

Templating                                                    Stable

                  The Symfony Components – Fabien Potencier
YAML
Event Dispatcher
                                                              PHP Quebec 2009
Templating
Dependency Injection Container
Console
Routing                                                       ConFoo 2010
Output Escaper
Request Handler
                  The Symfony Components – Fabien Potencier
Download / Installation




The Symfony Components – Fabien Potencier
git clone git://github.com/symfony/symfony.git




                                                            Main repository


                The Symfony Components – Fabien Potencier
svn checkout http://svn.symfony-project.org/branches/2.0/


                                                                  Git Mirror
                                                                Synchronized
                                                               every 15 minutes


                   The Symfony Components – Fabien Potencier
curl -O http://github.com/symfony/symfony/tarball/master
tar zxpf symfony-symfony-XXXXXXX.tar.gz

curl -O http://github.com/symfony/symfony/zipball/master
unzip symfony-symfony-XXXXXXX.zip



                                                               Nightly build


                   The Symfony Components – Fabien Potencier
app/
  .../
     Symfony/
       Components/
       Foundation/
       Framework/
        The Symfony Components – Fabien Potencier
Autoloading Classes




The Symfony Components – Fabien Potencier
Before PHP 5.3
PEAR naming convention
      The Symfony Components – Fabien Potencier
PEAR_Log                >      PEAR/Log.php
            Zend_Log                >      Zend/Log.php
  Swift_Mime_Message                >      Swift/Mime/Message.php
Doctrine_Pager_Range                >      Doctrine/Pager/Range.php
       Twig_Node_For                >      Twig/Node/For.php




               The Symfony Components – Fabien Potencier
PEAR_Log                >      PEAR/Log.php
            Zend_Log                >      Zend/Log.php
  Swift_Mime_Message                >      Swift/Mime/Message.php
Doctrine_Pager_Range                >      Doctrine/Pager/Range.php
       Twig_Node_For                >      Twig/Node/For.php

                                                           Vendor name

               The Symfony Components – Fabien Potencier
As of PHP 5.3
    PHP 5.3 technical
interoperability standards
       The Symfony Components – Fabien Potencier
SymfonyFoundationKernel > Symfony/Foundation/Kernel.php
     DoctrineDBALDriver > Doctrine/DBAL/Driver.php
pdependreflectionReflectionSession > pdepend/reflection/ReflectionSession.php




                         The Symfony Components – Fabien Potencier
SymfonyFoundationKernel > Symfony/Foundation/Kernel.php
     DoctrineDBALDriver > Doctrine/DBAL/Driver.php
pdependreflectionReflectionSession > pdepend/reflection/ReflectionSession.php




                                                                     Vendor name

                         The Symfony Components – Fabien Potencier
PHP 5.3 technical interoperability standards

             « … describes the mandatory requirements
                       that must be adhered to
                   for autoloader interoperability »


http://groups.google.com/group/php-standards/web/psr-0-final-proposal




                      The Symfony Components – Fabien Potencier
use SymfonyFoundationUniversalClassLoader;




              The Symfony Components – Fabien Potencier
require_once '.../Symfony/Foundation/UniversalClassLoader.php';

use SymfonyFoundationUniversalClassLoader;

$loader = new UniversalClassLoader();
$loader->registerNamespace(
   'Symfony', __DIR__.'/src/symfony/src'
);
$loader->register();

// use any Symfony class




                      The Symfony Components – Fabien Potencier
$loader->registerNamespaces(array(
  'Symfony' => '/path/to/symfony/src',
  'Doctrine' => '/path/to/doctrine/lib',
  'pdepend' => '/path/to/reflection/source',
));

                                                                PHP 5.3 technical
                                                            interoperability standards


                The Symfony Components – Fabien Potencier
$loader->registerPrefixes(array(
  'Swift_' => '/path/to/swiftmailer/lib/classes',
  'Zend_' => '/path/to/vendor/zend/library',
));


                                                             PEAR style


                 The Symfony Components – Fabien Potencier
require_once '.../Symfony/Foundation/UniversalClassLoader.php';

use SymfonyFoundationUniversalClassLoader;

$loader = new UniversalClassLoader();
$loader->registerNamespaces(array(
  'Symfony' => '/path/to/symfony/src',
  'Doctrine' => '/path/to/doctrine/lib',
));
$loader->registerPrefixes(array(
  'Swift_' => '/path/to/swiftmailer/lib/classes',
  'Zend_' => '/path/to/vendor/zend/library',
));
$loader->register();

// use any class

                     The Symfony Components – Fabien Potencier
Console




The Symfony Components – Fabien Potencier
Console




The Symfony Components – Fabien Potencier
Automate things
   code generators
     deployment

   The Symfony Components – Fabien Potencier
Long running tasks
          deployment
get « things » from the Internet

        The Symfony Components – Fabien Potencier
Batches
cleanup a database from time to time
    migrate a DB to a new schema

          The Symfony Components – Fabien Potencier
These tasks should never
  be run from a browser

       The Symfony Components – Fabien Potencier
But PHP is
a web language, right?
      The Symfony Components – Fabien Potencier
So, why not use the right tool
         for the job?

   … like Perl or Python?
         The Symfony Components – Fabien Potencier
Don’t want to use/learn another language
          Want to share code


            The Symfony Components – Fabien Potencier
PHP natively supports
 the CLI environment

      The Symfony Components – Fabien Potencier
<?php

// ...



         The Symfony Components – Fabien Potencier
#!/usr/bin/env php
<?php

// ...
                                                      $ ./foo …

          The Symfony Components – Fabien Potencier
$ ./foobar Fabien

$name = $argv[1];
echo 'Hello '.$name;


          The Symfony Components – Fabien Potencier
… but the complexity lies in the details



            The Symfony Components – Fabien Potencier
option / arguments handling
          exit codes
             shell
     output colorization
             tests
       error messages
              …
     The Symfony Components – Fabien Potencier
$ ./life foo "foo bar" --foo foobar -b

Array
(
    [0]   =>   ./life
    [1]   =>   foo
    [2]   =>   foo bar
    [3]   =>   --foo
    [4]   =>   foobar
    [5]   =>   -b
)

                    The Symfony Components – Fabien Potencier
don’t reinvent the wheel…
     use a “framework”

       The Symfony Components – Fabien Potencier
Console




The Symfony Components – Fabien Potencier
Let’s create a CLI tool
  to get the weather
anywhere in the world
      The Symfony Components – Fabien Potencier
The Symfony Components – Fabien Potencier
use LifeYahooWeather;

$weather = new YahooWeather('API_KEY', $argv[1]);
echo $weather->getTitle()."n";

$attrs = $weather->getCurrentConditions();

echo "Current conditions:n";
echo sprintf(" %s, %sCn", $attrs['text'], $attrs['temp']);

$attrs = $weather->getForecast();

echo sprintf("nForecast for %sn", $attrs['date']);
echo sprintf(" %s, low: %s, high: %sn", $attrs['text'],
$attrs['low'], $attrs['high']);


                         The Symfony Components – Fabien Potencier
use SymfonyComponentsConsoleApplication;

$application = new Application();
$application->run();




                The Symfony Components – Fabien Potencier
$command = new Command('weather');
$command->setCode(
   function ($input, $output)
   {
     // do something
   }
);

$application->addCommand($command);


                The Symfony Components – Fabien Potencier
use SymfonyComponentsConsoleApplication;

$application = new Application();
$application->addCommand(new WeatherCommand());
$application->run();




                The Symfony Components – Fabien Potencier
use SymfonyComponentsConsoleCommandCommand;
use SymfonyComponentsConsoleInputInputInterface;
use SymfonyComponentsConsoleOutputOutputInterface;

class WeatherCommand extends Command
{
  protected function configure()
  {
    $this->setName('weather');
  }

  protected function execute(InputInterface $input, OutputInterface
$output)
  {
    // do something
  }
}


                        The Symfony Components – Fabien Potencier
Console

    The Output



The Symfony Components – Fabien Potencier
$output->writeln($weather->getTitle());




                  The Symfony Components – Fabien Potencier
$output->writeln(
   sprintf('<info>%s</info>', $weather->getTitle())
);

$output->writeln("<comment>Conditions</comment>");




                  The Symfony Components – Fabien Potencier
The Symfony Components – Fabien Potencier
The Symfony Components – Fabien Potencier
Console

    Getting help



The Symfony Components – Fabien Potencier
The Symfony Components – Fabien Potencier
$application = new Application('Life Tool', '0.1');




                  The Symfony Components – Fabien Potencier
class WeatherCommand extends Command
{
  protected function configure()
  {
    $this->setName('weather')
      ->setDescription('Displays weather forecast')
      ->setHelp(<<<EOF
The <info>weather</info> command displays
weather forecast for a given city:

 <info>./life weather Paris</info>

You can also change the default degree unit
with the <comment>--unit</comment> option:

  <info>./life weather Paris --unit=c</info>
  <info>./life weather Paris -u c</info>
EOF
    );
  }

                         The Symfony Components – Fabien Potencier
The Symfony Components – Fabien Potencier
The Symfony Components – Fabien Potencier
$ ./life weather
$ ./life weath
$ ./life w
      The Symfony Components – Fabien Potencier
Console

    The Input



The Symfony Components – Fabien Potencier
class WeatherCommand extends Command
{
  protected function configure()
  {
    $definition = array(
      new InputArgument('place',
InputArgument::OPTIONAL, 'The place name', 'Paris'),

       new InputOption('unit', 'u',
InputOption::PARAMETER_REQUIRED, 'The degree unit',
'c'),
    );

    $this->setDefinition($definition);

                   The Symfony Components – Fabien Potencier
The Symfony Components – Fabien Potencier
protected function execute(InputInterface $input,
OutputInterface $output)
{
  $city = $input->getArgument('place');
  $unit = $input->getOption('unit');

    $output->writeln("<comment>Conditions</comment>");
}




                    The Symfony Components – Fabien Potencier
Console

    Error codes / Exit status



The Symfony Components – Fabien Potencier
The Symfony Components – Fabien Potencier
The Symfony Components – Fabien Potencier
protected function execute(InputInterface $input,
OutputInterface $output)
{
  $city = $input->getArgument('place');
  $unit = $input->getOption('unit');

    $output->writeln("<comment>Conditions</comment>");

    return 120;
}



                    The Symfony Components – Fabien Potencier
Console

    Interact with the user



The Symfony Components – Fabien Potencier
protected function interact($input, $output)
{
  $city = $this->dialog->ask(
     $output,
     '<comment>Which city?</comment> (Paris)',
     'Paris’
  );

    $input->setArgument('place', $city);
}



                    The Symfony Components – Fabien Potencier
./life weather --no-interaction




           The Symfony Components – Fabien Potencier
dialog
  ask()
  askConfirmation()
  askAndValidate()

formatter
  formatSection()
  formatBlock()

... your own



                The Symfony Components – Fabien Potencier
class WeatherHelper extends Helper
{
  public function __construct()
  {
    Output::setStyle('weather_hot', array('bg' => 'red', 'fg' => 'yellow'));
    Output::setStyle('weather_cold', array('bg' => 'blue', 'fg' => 'white'));
  }

    public function formatTemperature($temperature, $unit)
    {
      $style = $temperature < 0 ? 'weather_cold' : 'weather_hot';

    return sprintf("<%s> %s%s </%s>", $style, $temperature, strtoupper($unit),
$style);
  }

    public function getName()
    {
      return 'weather';
    }
}

                                The Symfony Components – Fabien Potencier
$output->writeln(sprintf(
  " %s, low: %s, high: %s",
  $attrs['text'],
  $this->weather->formatTemperature(
    $attrs['low'],
    $input->getOption('unit')),
  $this->weather->formatTemperature(
    $attrs['high'],
    $input->getOption('unit'))
));



                  The Symfony Components – Fabien Potencier
The Symfony Components – Fabien Potencier
Console

    Testing



The Symfony Components – Fabien Potencier
$input = new ArrayInput(
   array('place' => 'Paris', '--unit' => 'C')
);
$application->run($input);

$input = new StringInput('Paris --unit=C');
$application->run($input);



                The Symfony Components – Fabien Potencier
$stream = fopen('php://memory', 'a', false);
$output = new StreamOutput($stream);

$application->run($input, $output);

rewind($output->getStream());
echo stream_get_contents($output->getStream());



                The Symfony Components – Fabien Potencier
$application = new Application();

// for testing
$application->setCatchExceptions(false);
$application->setAutoExit(false);



             The Symfony Components – Fabien Potencier
echo $application->asXml();




           The Symfony Components – Fabien Potencier
$command = new WeatherCommand();
echo $command->asXml();




           The Symfony Components – Fabien Potencier
Create a PHAR archive
  out of your CLI tool
    for distribution
     The Symfony Components – Fabien Potencier
$pharFile = 'life.phar’;
if (file_exists($pharFile))
  unlink($pharFile);

$phar = new Phar($pharFile, 0, $this->application->getName());
$phar->setSignatureAlgorithm(Phar::SHA1);
$phar->startBuffering();

// CLI Component files
foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator(__DIR__.'/../symfony/src/Symfony/Components/
Console'), RecursiveIteratorIterator::LEAVES_ONLY) as $file)
{
  $phar['Symfony/Components/Console'.str_replace(__DIR__.'/../symfony/src/Symfony/Components/Console', '', $file)] =
file_get_contents($file);
}
// Life stuff
foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator(__DIR__.'/../Life'),
RecursiveIteratorIterator::LEAVES_ONLY) as $file)
{
  $phar['Life'.str_replace(__DIR__.'/../Life', '', $file)] = file_get_contents($file);
}
// Autoloader
$phar['Symfony/Foundation/UniversalClassLoader.php'] = file_get_contents(__DIR__.'/../symfony/src/Symfony/Foundation/
UniversalClassLoader.php');

// Stubs
$phar['_cli_stub.php'] = $this->getCliStub();
$phar['_web_stub.php'] = $this->getWebStub();
$phar->setDefaultStub('_cli_stub.php', '_web_stub.php');
$phar->stopBuffering();
$phar->compressFiles(Phar::GZ);
unset($phar);

                                       The Symfony Components – Fabien Potencier
git clone http://github.com/fabpot/confoo2010




                The Symfony Components – Fabien Potencier
Routing

    Pretty and Smart URLs



The Symfony Components – Fabien Potencier
http://example.com/article.php?id=44

http://example.com/article/confoo-2010




            The Symfony Components – Fabien Potencier
Routing is a two-way process
   Matching incoming requests (URLs)
           Generating URLs


           The Symfony Components – Fabien Potencier
The architecture
is difficult to get right

     The Symfony Components – Fabien Potencier
Symfony one is built
with performance in mind

      The Symfony Components – Fabien Potencier
Routing

    Describing your routes



The Symfony Components – Fabien Potencier
use SymfonyComponentsRoutingRouteCollection;
use SymfonyComponentsRoutingRoute;

$routes = new RouteCollection();
$route = new Route(
   '/',
   array('to' => function () { echo "Home!"; })
);
$routes->addRoute('home', $route);


                The Symfony Components – Fabien Potencier
$route = new Route(
   '/:year/:month/:day/:slug',
   array('to' => function ($params) { var_export
($params); }),
   array('year' => 'd{4}')
);
$routes->addRoute('blog_post', $route);



                The Symfony Components – Fabien Potencier
Routing

    Matching URLs



The Symfony Components – Fabien Potencier
use SymfonyComponentsRoutingMatcherUrlMatcher;

$matcher = new UrlMatcher($routes);

if (false === $params = $matcher->match('/'))
{
  throw new Exception('No route matches.');
}

$params['to']();


                   The Symfony Components – Fabien Potencier
$params = $matcher->match('/2010/03/10/confoo');
if (false === $params)
{
  throw new Exception('No route matches.');
}

$params['to']($params);



                The Symfony Components – Fabien Potencier
array (
  'to' =>
  Closure::__set_state(array(
  )),
  'year' => '2010',
  'month' => '03',
  'day' => '10',
  'slug' => 'confoo',
  '_route' => 'blog_post',
)

                The Symfony Components – Fabien Potencier
$params = $matcher->match('/yyyy/03/10/confoo');
if (false === $params)
{
  throw new Exception('No route matches.');
}

$params['to']($params);

Uncaught exception 'Exception' with message 'No
route matches.'


                The Symfony Components – Fabien Potencier
Routing

    Generating URLs



The Symfony Components – Fabien Potencier
use SymfonyComponentsRoutingGeneratorUrlGenerator;

$generator = new UrlGenerator($routes);

echo $generator->generate('home', array());




                  The Symfony Components – Fabien Potencier
$params =    array(
   'year'    => 2010,
   'month'   => 10,
   'day'     => 10,
   'slug'    => 'another-one'
);

echo $generator->generate('blog_post', $params);



                   The Symfony Components – Fabien Potencier
$params =    array(
   'year'    => 'yyyy',
   'month'   => 10,
   'day'     => 10,
);

echo $generator->generate('blog_post', $params);

Uncaught exception 'InvalidArgumentException'
with message 'The "blog_post" route has some
missing mandatory parameters (:slug).'

                   The Symfony Components – Fabien Potencier
use SymfonyComponentsRoutingGeneratorUrlGenerator;

$generator = new UrlGenerator($routes);

echo $generator->generate('home', array('foo' =>
'bar'));


/?foo=bar



                  The Symfony Components – Fabien Potencier
$generator = new   UrlGenerator($routes, array(
  'base_url' =>    '/myapp',
  'host'      =>   'www.example.com',
  'is_secure' =>   false,
));

echo $generator->generate('home', array(), true);


http://www.example.com/myapp/


                   The Symfony Components – Fabien Potencier
The context
        makes the routing
decoupled from the rest of the world

                      base_url
                        host
                     is_secure
                       method

      The Symfony Components – Fabien Potencier
Routing

    Describing your routes with XML or YAML



The Symfony Components – Fabien Potencier
home:
  pattern: /
  defaults: { controller: home, action: index }

blog_post:
  pattern: /:year/:month/:day/:slug
  defaults:
    controller: blog
    action:     show
  requirements:
    year: d{4}


                The Symfony Components – Fabien Potencier
use SymfonyComponentsRoutingLoaderYamlFileLoader;

$loader = new YamlFileLoader();

$routes = $loader->load('routes.yml');




                  The Symfony Components – Fabien Potencier
<?xml version="1.0" encoding="UTF-8" ?>

<routes xmlns="http://www.symfony-project.org/schema/routing"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.symfony-project.org/schema/routing
http://www.symfony-project.org/schema/routing/routing-1.0.xsd">

 <route id="blog_post" pattern="/:year/:month/:day/:slug">
   <default key="controller">blog</default>
   <default key="action">show</default>
   <requirement key="year">d{4}</requirement>
 </route>

  <route id="home" pattern="/">
    <default key="controller">home</default>
    <default key="action">index</default>
  </route>
</routes>

                       The Symfony Components – Fabien Potencier
use SymfonyComponentsRoutingLoaderXmlFileLoader;

$loader = new XmlFileLoader();

$routes = $loader->load('routes.xml');




                  The Symfony Components – Fabien Potencier
<?xml version="1.0" encoding="UTF-8" ?>

<routes>
  <route id="home" pattern="/">
    <default key="controller">home</default>
    <default key="action">index</default>
  </route>

  <import resource="blog.yml" prefix="/blog" />
  <import resource="forum.xml" prefix="/forum" />
</routes>

                 The Symfony Components – Fabien Potencier
home:
  pattern: /
  defaults: { controller: home, action: index }

import:
  - { resource: blog.yml, prefix: /blog }
  - { resource: forum.xml, prefix: /forum }



                The Symfony Components – Fabien Potencier
$yamlLoader = new YamlFileLoader();
$xmlLoader = new XmlFileLoader();

$routes = new RouteCollection();
$route = new Route(
   '/',
   array('to' => function () { echo "Home!"; })
);
$routes->addRoute('home', $route);

$routes->addCollection(
  $yamlLoader->load('blog.yml'), '/blog');

$routes->addCollection(
  $xmlLoader->load('forum.xml'), '/forum');
                   The Symfony Components – Fabien Potencier
/blog/2010/03/10/confoo
 prefix                                      pattern




         The Symfony Components – Fabien Potencier
Routing

    Make it simple & fast



The Symfony Components – Fabien Potencier
use SymfonyComponentsRoutingRouter;

$router = new Router($loader, $options, $context);




                  The Symfony Components – Fabien Potencier
$loader = function ()
{
  $routes = new RouteCollection();
  // ...

  return $routes;
};

$context = array(
   'base_url' => '/myapp',
   'host'      => 'www.example.com',
   'is_secure' => false,
);

$options = array(
   'cache_dir' => '/tmp/routing',
   'debug'     => true,
);
                       The Symfony Components – Fabien Potencier
$router = new Router($loader, $options, $context);

if (false === $params = $router->match('/'))
{
  throw new Exception('No route matches.');
}

echo $router->generate('home', array());




                  The Symfony Components – Fabien Potencier
class ProjectUrlMatcher extends SymfonyComponentsRouting
MatcherUrlMatcher
{
  // ...

    public function match($url)
    {
      $url = $this->normalizeUrl($url);

      if (preg_match('#^/$#x', $url, $matches))
        return array_merge($this->mergeDefaults($matches, array
(    'to' => 'foo',)), array('_route' => 'home'));

        return false;
    }
}

                        The Symfony Components – Fabien Potencier
class ProjectUrlGenerator extends SymfonyComponentsRoutingGeneratorUrlGenerator
{
  // ...

 public function generate($name, array $parameters, $absolute = false)
 {
   if (!method_exists($this, $method = 'get'.$name.'RouteInfo'))
   {
     throw new InvalidArgumentException(sprintf('Route "%s" does not exist.', $name));
   }

    list($variables, $defaults, $requirements, $tokens) = $this->$method();

    return $this->doGenerate($variables, $defaults, $requirements, $tokens, $parameters,
$name, $absolute);
  }

  protected function gethomeRouteInfo()
  {
    return array(array (), array_merge($this->defaults, array ( 'to' => 'foo',)), array
(), array ( 0 =>    array (    0 => 'text',    1 => '/',    2 => '',   3 => NULL, ),));
  }
}

                              The Symfony Components – Fabien Potencier
use SymfonyComponentsRoutingFileResource;

$loader = function ()
{
  $routes = new RouteCollection();
  // ...

  $routes->addResource(new FileResource(__FILE__));

  return $routes;
};


                    The Symfony Components – Fabien Potencier
Routing

    Make it really fast



The Symfony Components – Fabien Potencier
use SymfonyComponentsRoutingMatcherDumper
ApacheMatcherDumper;

$dumper = new ApacheMatcherDumper($routes);

echo $dumper->dump();




                The Symfony Components – Fabien Potencier
RewriteCond %{PATH_INFO} ^/$
RewriteRule .* index.php
[QSA,L,E=_ROUTING__route:home,E=_ROUTING_to:foo
]




                The Symfony Components – Fabien Potencier
$options = array(
   'cache_dir'     => '/tmp/routing',
   'debug'         => true,
   'matcher_class' => 'SymfonyComponents
RoutingMatcherApacheUrlMatcher',
);




                The Symfony Components – Fabien Potencier
Output Escaper




The Symfony Components – Fabien Potencier
Provides XSS protection
 for your PHP templates

      The Symfony Components – Fabien Potencier
Wraps template variables
Works for
   strings
   arrays
   objects
      properties
      methods
      __call(), __get(), …
      Iterators, Coutables, …
      …
Works for deep method calls
                         The Symfony Components – Fabien Potencier
use SymfonyComponentsOutputEscaperEscaper;

$title = 'Foo <br />';

echo Escaper::escape('htmlspecialchars', $title);




                     The Symfony Components – Fabien Potencier
use SymfonyComponentsOutputEscaperEscaper;

$article = array(
   'title' => 'Foo <br />',
   'author' => array(
     'name' => 'Fabien <br/>',
   )
);

$article = Escaper::escape('htmlspecialchars', $article);

echo $article['title']."n";
echo $article['author']['name']."n";


                      The Symfony Components – Fabien Potencier
class Article
{
  protected $title;
  protected $author;

    public $full_title;    public property

    public function __construct($title, Author $author)
    {
      $this->title = $title;
      $this->full_title = $title;
      $this->author = $author;
    }
                                                                         public method
    public function getTitle() { return $this->title; }
    public function getAuthor() { return $this->author; }                     public method returning
    public function __get($key) { return $this->$key; }                       another object
    public function __call($method, $arguments)
    {                                                                       magic __get()
      return $this->{'get'.$method}();     magic __call()
    }
}
                             The Symfony Components – Fabien Potencier
class Author
{
  protected $name;

    public function __construct($name) { $this->name = $name; }
    public function getName() { return $this->name; }
}




                       The Symfony Components – Fabien Potencier
use SymfonyComponentsOutputEscaperEscaper;

$article = new Article(
   'foo <br />',
   new Author('Fabien <br />')
);

$article = Escaper::escape('htmlspecialchars', $article);

echo   $article->getTitle()."n";
echo   $article->getAuthor()->getName()."n";
echo   $article->full_title."n";
echo   $article->title."n";
echo   $article->title()."n";


                       The Symfony Components – Fabien Potencier
explicitly ask
                                                              for raw data


echo $article->getHtmlContent('raw');



echo $article->getTitle('js');
                                             change the default
                                             escaping strategy



                The Symfony Components – Fabien Potencier
Request Handler




The Symfony Components – Fabien Potencier
use SymfonyComponentsRequestHandlerRequest;

$request = new Request();
$request->getPathInfo();
$request->getPreferredLanguage(array('en', 'fr'));
$request->isXmlHttpRequest();




                 The Symfony Components – Fabien Potencier
use SymfonyComponentsRequestHandlerRequest;

$request = new   Request(array(
  'request' =>   $_POST,
  'query'   =>   $_GET,
  'path'    =>   array(),
  'server' =>    $_SERVER,
));



                  The Symfony Components – Fabien Potencier
use SymfonyComponentsRequestHandlerResponse;

$response = new Response('Hello World', 200,
  array('Content-Type' => 'text/plain'));
$response->send();

$response->setHeader('Content-Type', 'text/plain');
$response->setCookie('foo', 'bar');
$response->setContent('Hello World');
$response->setStatusCode(200);



                  The Symfony Components – Fabien Potencier
Request Handler

    Framework to build Frameworks



The Symfony Components – Fabien Potencier
use SymfonyComponentsRequestHandlerRequest;
use SymfonyComponentsRequestHandlerResponse;
use SymfonyComponentsRequestHandlerRequestHandler;

$handler = new RequestHandler($dispatcher);

$request = new Request();
$response = $handler->handle($request);
$response->send();



                  The Symfony Components – Fabien Potencier
use SymfonyComponentsEventDispatcherEventDispatcher;
use SymfonyComponentsEventDispatcherEvent;

$dispatcher = new EventDispatcher();
$dispatcher->connect('core.load_controller', function (Event $event)
{
  $event->setReturnValue(array(
    function ($request) { return new Response('Hello!'); },
    array($event['request'])
  ));

  return true;
});




                         The Symfony Components – Fabien Potencier
Request Handler

    A small Framework



The Symfony Components – Fabien Potencier
$framework = new Framework(array(
  '/' => function ($request)
  {
    $content = 'Hello '.
      $request->getParameter('name');

    return new Response($content);
  }
));
$framework->run();

                The Symfony Components – Fabien Potencier
class Framework
{
  protected $map;

    public function __construct($map)
    {
      $this->map = $map;
    }

    public function run()
    {
      $dispatcher = new EventDispatcher();
      $dispatcher->connect('core.load_controller', array($this, 'loadController'));

        $handler = new RequestHandler($dispatcher);
        $response = $handler->handle(new Request());
        $response->send();
    }
}



                                The Symfony Components – Fabien Potencier
public function loadController(Event $event)
{
  $request = $event['request'];

    $routes = new RouteCollection();
    foreach ($this->map as $pattern => $to)
    {
      $route = new Route($pattern, array('to' => $to));
      $routes->addRoute(str_replace('/', '_', $pattern), $route);
    }

    $matcher = new UrlMatcher($routes, array(
      'base_url' => $request->getBaseUrl(),
      'method'    => $request->getMethod(),
      'host'      => $request->getHost(),
      'is_secure' => $request->isSecure(),
    ));

    $parameters = $matcher->match($request->getPathInfo());
    if (false === $parameters)
    {
      return false;
    }

    $request->setPathParameters($parameters);

    $event->setReturnValue(array($parameters['to'], array($request)));

    return true;
}
                                      The Symfony Components – Fabien Potencier
$framework = new Framework(array(
  '/' => function ($request)
  {
    $content = 'Hello '.
      $request->getParameter('name');

    return new Response($content);
  }
));
$framework->run();

                The Symfony Components – Fabien Potencier
Questions?




The Symfony Components – Fabien Potencier
Sensio S.A.
        92-98, boulevard Victor Hugo
            92 115 Clichy Cedex
                  FRANCE
             Tél. : +33 1 40 99 80 80

                  Contact
              Fabien Potencier
       fabien.potencier at sensio.com




   http://www.sensiolabs.com/
http://www.symfony-project.org/
 http://fabien.potencier.org/


The Symfony Components – Fabien Potencier

More Related Content

Similar to Symfony Components

Symfony Components 2.0 on PHP 5.3
Symfony Components 2.0 on PHP 5.3Symfony Components 2.0 on PHP 5.3
Symfony Components 2.0 on PHP 5.3Fabien Potencier
 
Fabien Potencier "Symfony 4 in action"
Fabien Potencier "Symfony 4 in action"Fabien Potencier "Symfony 4 in action"
Fabien Potencier "Symfony 4 in action"Fwdays
 
Symfony Components in the wild
Symfony Components in the wildSymfony Components in the wild
Symfony Components in the wildPHPLondon
 
Integrating symfony and Zend Framework
Integrating symfony and Zend FrameworkIntegrating symfony and Zend Framework
Integrating symfony and Zend FrameworkStefan Koopmanschap
 
Integrating symfony and Zend Framework (PHPNW09)
Integrating symfony and Zend Framework (PHPNW09)Integrating symfony and Zend Framework (PHPNW09)
Integrating symfony and Zend Framework (PHPNW09)Stefan Koopmanschap
 
Symfony2 San Francisco Meetup 2009
Symfony2 San Francisco Meetup 2009Symfony2 San Francisco Meetup 2009
Symfony2 San Francisco Meetup 2009Fabien Potencier
 
Integrating symfony and Zend Framework (PHPBarcelona 2009)
Integrating symfony and Zend Framework (PHPBarcelona 2009)Integrating symfony and Zend Framework (PHPBarcelona 2009)
Integrating symfony and Zend Framework (PHPBarcelona 2009)Stefan Koopmanschap
 
Symfony: A Brief Introduction
Symfony: A Brief IntroductionSymfony: A Brief Introduction
Symfony: A Brief IntroductionCraig Willis
 
An introduction to Symfony 2 for symfony 1 developers
An introduction to Symfony 2 for symfony 1 developersAn introduction to Symfony 2 for symfony 1 developers
An introduction to Symfony 2 for symfony 1 developersGiorgio Cefaro
 
Symfony2 components to the rescue of your PHP projects
Symfony2 components to the rescue of your PHP projectsSymfony2 components to the rescue of your PHP projects
Symfony2 components to the rescue of your PHP projectsXavier Lacot
 
A Glymse of Symfony 2
A Glymse of Symfony 2A Glymse of Symfony 2
A Glymse of Symfony 2shaduli
 
Symfony State Of The Union, March 2010
Symfony State Of The Union, March 2010Symfony State Of The Union, March 2010
Symfony State Of The Union, March 2010Damien Filiatrault
 
Write Plugins for symfony (Symfony Camp 2007)
Write Plugins for symfony (Symfony Camp 2007)Write Plugins for symfony (Symfony Camp 2007)
Write Plugins for symfony (Symfony Camp 2007)Fabien Potencier
 

Similar to Symfony Components (20)

симфони это не страшно
симфони   это не страшносимфони   это не страшно
симфони это не страшно
 
Drupal symfony
Drupal symfonyDrupal symfony
Drupal symfony
 
Symfony Components 2.0 on PHP 5.3
Symfony Components 2.0 on PHP 5.3Symfony Components 2.0 on PHP 5.3
Symfony Components 2.0 on PHP 5.3
 
Symfony 2.0 on PHP 5.3
Symfony 2.0 on PHP 5.3Symfony 2.0 on PHP 5.3
Symfony 2.0 on PHP 5.3
 
Fabien Potencier "Symfony 4 in action"
Fabien Potencier "Symfony 4 in action"Fabien Potencier "Symfony 4 in action"
Fabien Potencier "Symfony 4 in action"
 
Symfony Components in the wild
Symfony Components in the wildSymfony Components in the wild
Symfony Components in the wild
 
Running Symfony
Running SymfonyRunning Symfony
Running Symfony
 
Integrating symfony and Zend Framework
Integrating symfony and Zend FrameworkIntegrating symfony and Zend Framework
Integrating symfony and Zend Framework
 
Integrating symfony and Zend Framework (PHPNW09)
Integrating symfony and Zend Framework (PHPNW09)Integrating symfony and Zend Framework (PHPNW09)
Integrating symfony and Zend Framework (PHPNW09)
 
PHP 5.3 in practice
PHP 5.3 in practicePHP 5.3 in practice
PHP 5.3 in practice
 
Symfony2 San Francisco Meetup 2009
Symfony2 San Francisco Meetup 2009Symfony2 San Francisco Meetup 2009
Symfony2 San Francisco Meetup 2009
 
Integrating symfony and Zend Framework (PHPBarcelona 2009)
Integrating symfony and Zend Framework (PHPBarcelona 2009)Integrating symfony and Zend Framework (PHPBarcelona 2009)
Integrating symfony and Zend Framework (PHPBarcelona 2009)
 
Symfony 4 & Flex news
Symfony 4 & Flex newsSymfony 4 & Flex news
Symfony 4 & Flex news
 
Symfony: A Brief Introduction
Symfony: A Brief IntroductionSymfony: A Brief Introduction
Symfony: A Brief Introduction
 
An introduction to Symfony 2 for symfony 1 developers
An introduction to Symfony 2 for symfony 1 developersAn introduction to Symfony 2 for symfony 1 developers
An introduction to Symfony 2 for symfony 1 developers
 
CPAN For Private Code
CPAN For Private CodeCPAN For Private Code
CPAN For Private Code
 
Symfony2 components to the rescue of your PHP projects
Symfony2 components to the rescue of your PHP projectsSymfony2 components to the rescue of your PHP projects
Symfony2 components to the rescue of your PHP projects
 
A Glymse of Symfony 2
A Glymse of Symfony 2A Glymse of Symfony 2
A Glymse of Symfony 2
 
Symfony State Of The Union, March 2010
Symfony State Of The Union, March 2010Symfony State Of The Union, March 2010
Symfony State Of The Union, March 2010
 
Write Plugins for symfony (Symfony Camp 2007)
Write Plugins for symfony (Symfony Camp 2007)Write Plugins for symfony (Symfony Camp 2007)
Write Plugins for symfony (Symfony Camp 2007)
 

Recently uploaded

Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobeapidays
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdflior mazor
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsRoshan Dwivedi
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherRemote DBA Services
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century educationjfdjdjcjdnsjd
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyKhushali Kathiriya
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MIND CTI
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businesspanagenda
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...DianaGray10
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAndrey Devyatkin
 
Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024The Digital Insurer
 

Recently uploaded (20)

Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024
 

Symfony Components

  • 1. The Symfony Components – Fabien Potencier
  • 2. Serial entrepreneur Developer by passion Founder of Sensio Creator and lead developer of Symfony On Twitter @fabpot On github http://www.github.com/fabpot http://fabien.potencier.org/ The Symfony Components – Fabien Potencier
  • 3. Standalone components for PHP 5.3 No dependency between them Used extensively in Symfony 2, the framework The Symfony Components – Fabien Potencier
  • 4. Low-level libraries needed by most websites The Symfony Components – Fabien Potencier
  • 5. Event Dispatcher Stable Output Escaper Stable Extracted from symfony 1 YAML Stable Routing Beta Console Stable Dependency Injection Container Stable Written from scratch for Symfony 2 Request Handler Stable Templating Stable The Symfony Components – Fabien Potencier
  • 6. YAML Event Dispatcher PHP Quebec 2009 Templating Dependency Injection Container Console Routing ConFoo 2010 Output Escaper Request Handler The Symfony Components – Fabien Potencier
  • 7. Download / Installation The Symfony Components – Fabien Potencier
  • 8. git clone git://github.com/symfony/symfony.git Main repository The Symfony Components – Fabien Potencier
  • 9. svn checkout http://svn.symfony-project.org/branches/2.0/ Git Mirror Synchronized every 15 minutes The Symfony Components – Fabien Potencier
  • 10. curl -O http://github.com/symfony/symfony/tarball/master tar zxpf symfony-symfony-XXXXXXX.tar.gz curl -O http://github.com/symfony/symfony/zipball/master unzip symfony-symfony-XXXXXXX.zip Nightly build The Symfony Components – Fabien Potencier
  • 11. app/ .../ Symfony/ Components/ Foundation/ Framework/ The Symfony Components – Fabien Potencier
  • 12. Autoloading Classes The Symfony Components – Fabien Potencier
  • 13. Before PHP 5.3 PEAR naming convention The Symfony Components – Fabien Potencier
  • 14. PEAR_Log > PEAR/Log.php Zend_Log > Zend/Log.php Swift_Mime_Message > Swift/Mime/Message.php Doctrine_Pager_Range > Doctrine/Pager/Range.php Twig_Node_For > Twig/Node/For.php The Symfony Components – Fabien Potencier
  • 15. PEAR_Log > PEAR/Log.php Zend_Log > Zend/Log.php Swift_Mime_Message > Swift/Mime/Message.php Doctrine_Pager_Range > Doctrine/Pager/Range.php Twig_Node_For > Twig/Node/For.php Vendor name The Symfony Components – Fabien Potencier
  • 16. As of PHP 5.3 PHP 5.3 technical interoperability standards The Symfony Components – Fabien Potencier
  • 17. SymfonyFoundationKernel > Symfony/Foundation/Kernel.php DoctrineDBALDriver > Doctrine/DBAL/Driver.php pdependreflectionReflectionSession > pdepend/reflection/ReflectionSession.php The Symfony Components – Fabien Potencier
  • 18. SymfonyFoundationKernel > Symfony/Foundation/Kernel.php DoctrineDBALDriver > Doctrine/DBAL/Driver.php pdependreflectionReflectionSession > pdepend/reflection/ReflectionSession.php Vendor name The Symfony Components – Fabien Potencier
  • 19. PHP 5.3 technical interoperability standards « … describes the mandatory requirements that must be adhered to for autoloader interoperability » http://groups.google.com/group/php-standards/web/psr-0-final-proposal The Symfony Components – Fabien Potencier
  • 20. use SymfonyFoundationUniversalClassLoader; The Symfony Components – Fabien Potencier
  • 21. require_once '.../Symfony/Foundation/UniversalClassLoader.php'; use SymfonyFoundationUniversalClassLoader; $loader = new UniversalClassLoader(); $loader->registerNamespace( 'Symfony', __DIR__.'/src/symfony/src' ); $loader->register(); // use any Symfony class The Symfony Components – Fabien Potencier
  • 22. $loader->registerNamespaces(array( 'Symfony' => '/path/to/symfony/src', 'Doctrine' => '/path/to/doctrine/lib', 'pdepend' => '/path/to/reflection/source', )); PHP 5.3 technical interoperability standards The Symfony Components – Fabien Potencier
  • 23. $loader->registerPrefixes(array( 'Swift_' => '/path/to/swiftmailer/lib/classes', 'Zend_' => '/path/to/vendor/zend/library', )); PEAR style The Symfony Components – Fabien Potencier
  • 24. require_once '.../Symfony/Foundation/UniversalClassLoader.php'; use SymfonyFoundationUniversalClassLoader; $loader = new UniversalClassLoader(); $loader->registerNamespaces(array( 'Symfony' => '/path/to/symfony/src', 'Doctrine' => '/path/to/doctrine/lib', )); $loader->registerPrefixes(array( 'Swift_' => '/path/to/swiftmailer/lib/classes', 'Zend_' => '/path/to/vendor/zend/library', )); $loader->register(); // use any class The Symfony Components – Fabien Potencier
  • 25. Console The Symfony Components – Fabien Potencier
  • 26. Console The Symfony Components – Fabien Potencier
  • 27. Automate things code generators deployment The Symfony Components – Fabien Potencier
  • 28. Long running tasks deployment get « things » from the Internet The Symfony Components – Fabien Potencier
  • 29. Batches cleanup a database from time to time migrate a DB to a new schema The Symfony Components – Fabien Potencier
  • 30. These tasks should never be run from a browser The Symfony Components – Fabien Potencier
  • 31. But PHP is a web language, right? The Symfony Components – Fabien Potencier
  • 32. So, why not use the right tool for the job? … like Perl or Python? The Symfony Components – Fabien Potencier
  • 33. Don’t want to use/learn another language Want to share code The Symfony Components – Fabien Potencier
  • 34. PHP natively supports the CLI environment The Symfony Components – Fabien Potencier
  • 35. <?php // ... The Symfony Components – Fabien Potencier
  • 36. #!/usr/bin/env php <?php // ... $ ./foo … The Symfony Components – Fabien Potencier
  • 37. $ ./foobar Fabien $name = $argv[1]; echo 'Hello '.$name; The Symfony Components – Fabien Potencier
  • 38. … but the complexity lies in the details The Symfony Components – Fabien Potencier
  • 39. option / arguments handling exit codes shell output colorization tests error messages … The Symfony Components – Fabien Potencier
  • 40. $ ./life foo "foo bar" --foo foobar -b Array ( [0] => ./life [1] => foo [2] => foo bar [3] => --foo [4] => foobar [5] => -b ) The Symfony Components – Fabien Potencier
  • 41. don’t reinvent the wheel… use a “framework” The Symfony Components – Fabien Potencier
  • 42. Console The Symfony Components – Fabien Potencier
  • 43. Let’s create a CLI tool to get the weather anywhere in the world The Symfony Components – Fabien Potencier
  • 44. The Symfony Components – Fabien Potencier
  • 45. use LifeYahooWeather; $weather = new YahooWeather('API_KEY', $argv[1]); echo $weather->getTitle()."n"; $attrs = $weather->getCurrentConditions(); echo "Current conditions:n"; echo sprintf(" %s, %sCn", $attrs['text'], $attrs['temp']); $attrs = $weather->getForecast(); echo sprintf("nForecast for %sn", $attrs['date']); echo sprintf(" %s, low: %s, high: %sn", $attrs['text'], $attrs['low'], $attrs['high']); The Symfony Components – Fabien Potencier
  • 46. use SymfonyComponentsConsoleApplication; $application = new Application(); $application->run(); The Symfony Components – Fabien Potencier
  • 47. $command = new Command('weather'); $command->setCode( function ($input, $output) { // do something } ); $application->addCommand($command); The Symfony Components – Fabien Potencier
  • 48. use SymfonyComponentsConsoleApplication; $application = new Application(); $application->addCommand(new WeatherCommand()); $application->run(); The Symfony Components – Fabien Potencier
  • 49. use SymfonyComponentsConsoleCommandCommand; use SymfonyComponentsConsoleInputInputInterface; use SymfonyComponentsConsoleOutputOutputInterface; class WeatherCommand extends Command { protected function configure() { $this->setName('weather'); } protected function execute(InputInterface $input, OutputInterface $output) { // do something } } The Symfony Components – Fabien Potencier
  • 50. Console The Output The Symfony Components – Fabien Potencier
  • 51. $output->writeln($weather->getTitle()); The Symfony Components – Fabien Potencier
  • 52. $output->writeln( sprintf('<info>%s</info>', $weather->getTitle()) ); $output->writeln("<comment>Conditions</comment>"); The Symfony Components – Fabien Potencier
  • 53. The Symfony Components – Fabien Potencier
  • 54. The Symfony Components – Fabien Potencier
  • 55. Console Getting help The Symfony Components – Fabien Potencier
  • 56. The Symfony Components – Fabien Potencier
  • 57. $application = new Application('Life Tool', '0.1'); The Symfony Components – Fabien Potencier
  • 58. class WeatherCommand extends Command { protected function configure() { $this->setName('weather') ->setDescription('Displays weather forecast') ->setHelp(<<<EOF The <info>weather</info> command displays weather forecast for a given city: <info>./life weather Paris</info> You can also change the default degree unit with the <comment>--unit</comment> option: <info>./life weather Paris --unit=c</info> <info>./life weather Paris -u c</info> EOF ); } The Symfony Components – Fabien Potencier
  • 59. The Symfony Components – Fabien Potencier
  • 60. The Symfony Components – Fabien Potencier
  • 61. $ ./life weather $ ./life weath $ ./life w The Symfony Components – Fabien Potencier
  • 62. Console The Input The Symfony Components – Fabien Potencier
  • 63. class WeatherCommand extends Command { protected function configure() { $definition = array( new InputArgument('place', InputArgument::OPTIONAL, 'The place name', 'Paris'), new InputOption('unit', 'u', InputOption::PARAMETER_REQUIRED, 'The degree unit', 'c'), ); $this->setDefinition($definition); The Symfony Components – Fabien Potencier
  • 64. The Symfony Components – Fabien Potencier
  • 65. protected function execute(InputInterface $input, OutputInterface $output) { $city = $input->getArgument('place'); $unit = $input->getOption('unit'); $output->writeln("<comment>Conditions</comment>"); } The Symfony Components – Fabien Potencier
  • 66. Console Error codes / Exit status The Symfony Components – Fabien Potencier
  • 67. The Symfony Components – Fabien Potencier
  • 68. The Symfony Components – Fabien Potencier
  • 69. protected function execute(InputInterface $input, OutputInterface $output) { $city = $input->getArgument('place'); $unit = $input->getOption('unit'); $output->writeln("<comment>Conditions</comment>"); return 120; } The Symfony Components – Fabien Potencier
  • 70. Console Interact with the user The Symfony Components – Fabien Potencier
  • 71. protected function interact($input, $output) { $city = $this->dialog->ask( $output, '<comment>Which city?</comment> (Paris)', 'Paris’ ); $input->setArgument('place', $city); } The Symfony Components – Fabien Potencier
  • 72. ./life weather --no-interaction The Symfony Components – Fabien Potencier
  • 73. dialog ask() askConfirmation() askAndValidate() formatter formatSection() formatBlock() ... your own The Symfony Components – Fabien Potencier
  • 74. class WeatherHelper extends Helper { public function __construct() { Output::setStyle('weather_hot', array('bg' => 'red', 'fg' => 'yellow')); Output::setStyle('weather_cold', array('bg' => 'blue', 'fg' => 'white')); } public function formatTemperature($temperature, $unit) { $style = $temperature < 0 ? 'weather_cold' : 'weather_hot'; return sprintf("<%s> %s%s </%s>", $style, $temperature, strtoupper($unit), $style); } public function getName() { return 'weather'; } } The Symfony Components – Fabien Potencier
  • 75. $output->writeln(sprintf( " %s, low: %s, high: %s", $attrs['text'], $this->weather->formatTemperature( $attrs['low'], $input->getOption('unit')), $this->weather->formatTemperature( $attrs['high'], $input->getOption('unit')) )); The Symfony Components – Fabien Potencier
  • 76. The Symfony Components – Fabien Potencier
  • 77. Console Testing The Symfony Components – Fabien Potencier
  • 78. $input = new ArrayInput( array('place' => 'Paris', '--unit' => 'C') ); $application->run($input); $input = new StringInput('Paris --unit=C'); $application->run($input); The Symfony Components – Fabien Potencier
  • 79. $stream = fopen('php://memory', 'a', false); $output = new StreamOutput($stream); $application->run($input, $output); rewind($output->getStream()); echo stream_get_contents($output->getStream()); The Symfony Components – Fabien Potencier
  • 80. $application = new Application(); // for testing $application->setCatchExceptions(false); $application->setAutoExit(false); The Symfony Components – Fabien Potencier
  • 81. echo $application->asXml(); The Symfony Components – Fabien Potencier
  • 82. $command = new WeatherCommand(); echo $command->asXml(); The Symfony Components – Fabien Potencier
  • 83. Create a PHAR archive out of your CLI tool for distribution The Symfony Components – Fabien Potencier
  • 84. $pharFile = 'life.phar’; if (file_exists($pharFile)) unlink($pharFile); $phar = new Phar($pharFile, 0, $this->application->getName()); $phar->setSignatureAlgorithm(Phar::SHA1); $phar->startBuffering(); // CLI Component files foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator(__DIR__.'/../symfony/src/Symfony/Components/ Console'), RecursiveIteratorIterator::LEAVES_ONLY) as $file) { $phar['Symfony/Components/Console'.str_replace(__DIR__.'/../symfony/src/Symfony/Components/Console', '', $file)] = file_get_contents($file); } // Life stuff foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator(__DIR__.'/../Life'), RecursiveIteratorIterator::LEAVES_ONLY) as $file) { $phar['Life'.str_replace(__DIR__.'/../Life', '', $file)] = file_get_contents($file); } // Autoloader $phar['Symfony/Foundation/UniversalClassLoader.php'] = file_get_contents(__DIR__.'/../symfony/src/Symfony/Foundation/ UniversalClassLoader.php'); // Stubs $phar['_cli_stub.php'] = $this->getCliStub(); $phar['_web_stub.php'] = $this->getWebStub(); $phar->setDefaultStub('_cli_stub.php', '_web_stub.php'); $phar->stopBuffering(); $phar->compressFiles(Phar::GZ); unset($phar); The Symfony Components – Fabien Potencier
  • 85. git clone http://github.com/fabpot/confoo2010 The Symfony Components – Fabien Potencier
  • 86. Routing Pretty and Smart URLs The Symfony Components – Fabien Potencier
  • 88. Routing is a two-way process Matching incoming requests (URLs) Generating URLs The Symfony Components – Fabien Potencier
  • 89. The architecture is difficult to get right The Symfony Components – Fabien Potencier
  • 90. Symfony one is built with performance in mind The Symfony Components – Fabien Potencier
  • 91. Routing Describing your routes The Symfony Components – Fabien Potencier
  • 92. use SymfonyComponentsRoutingRouteCollection; use SymfonyComponentsRoutingRoute; $routes = new RouteCollection(); $route = new Route( '/', array('to' => function () { echo "Home!"; }) ); $routes->addRoute('home', $route); The Symfony Components – Fabien Potencier
  • 93. $route = new Route( '/:year/:month/:day/:slug', array('to' => function ($params) { var_export ($params); }), array('year' => 'd{4}') ); $routes->addRoute('blog_post', $route); The Symfony Components – Fabien Potencier
  • 94. Routing Matching URLs The Symfony Components – Fabien Potencier
  • 95. use SymfonyComponentsRoutingMatcherUrlMatcher; $matcher = new UrlMatcher($routes); if (false === $params = $matcher->match('/')) { throw new Exception('No route matches.'); } $params['to'](); The Symfony Components – Fabien Potencier
  • 96. $params = $matcher->match('/2010/03/10/confoo'); if (false === $params) { throw new Exception('No route matches.'); } $params['to']($params); The Symfony Components – Fabien Potencier
  • 97. array ( 'to' => Closure::__set_state(array( )), 'year' => '2010', 'month' => '03', 'day' => '10', 'slug' => 'confoo', '_route' => 'blog_post', ) The Symfony Components – Fabien Potencier
  • 98. $params = $matcher->match('/yyyy/03/10/confoo'); if (false === $params) { throw new Exception('No route matches.'); } $params['to']($params); Uncaught exception 'Exception' with message 'No route matches.' The Symfony Components – Fabien Potencier
  • 99. Routing Generating URLs The Symfony Components – Fabien Potencier
  • 100. use SymfonyComponentsRoutingGeneratorUrlGenerator; $generator = new UrlGenerator($routes); echo $generator->generate('home', array()); The Symfony Components – Fabien Potencier
  • 101. $params = array( 'year' => 2010, 'month' => 10, 'day' => 10, 'slug' => 'another-one' ); echo $generator->generate('blog_post', $params); The Symfony Components – Fabien Potencier
  • 102. $params = array( 'year' => 'yyyy', 'month' => 10, 'day' => 10, ); echo $generator->generate('blog_post', $params); Uncaught exception 'InvalidArgumentException' with message 'The "blog_post" route has some missing mandatory parameters (:slug).' The Symfony Components – Fabien Potencier
  • 103. use SymfonyComponentsRoutingGeneratorUrlGenerator; $generator = new UrlGenerator($routes); echo $generator->generate('home', array('foo' => 'bar')); /?foo=bar The Symfony Components – Fabien Potencier
  • 104. $generator = new UrlGenerator($routes, array( 'base_url' => '/myapp', 'host' => 'www.example.com', 'is_secure' => false, )); echo $generator->generate('home', array(), true); http://www.example.com/myapp/ The Symfony Components – Fabien Potencier
  • 105. The context makes the routing decoupled from the rest of the world base_url host is_secure method The Symfony Components – Fabien Potencier
  • 106. Routing Describing your routes with XML or YAML The Symfony Components – Fabien Potencier
  • 107. home: pattern: / defaults: { controller: home, action: index } blog_post: pattern: /:year/:month/:day/:slug defaults: controller: blog action: show requirements: year: d{4} The Symfony Components – Fabien Potencier
  • 108. use SymfonyComponentsRoutingLoaderYamlFileLoader; $loader = new YamlFileLoader(); $routes = $loader->load('routes.yml'); The Symfony Components – Fabien Potencier
  • 109. <?xml version="1.0" encoding="UTF-8" ?> <routes xmlns="http://www.symfony-project.org/schema/routing" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.symfony-project.org/schema/routing http://www.symfony-project.org/schema/routing/routing-1.0.xsd"> <route id="blog_post" pattern="/:year/:month/:day/:slug"> <default key="controller">blog</default> <default key="action">show</default> <requirement key="year">d{4}</requirement> </route> <route id="home" pattern="/"> <default key="controller">home</default> <default key="action">index</default> </route> </routes> The Symfony Components – Fabien Potencier
  • 110. use SymfonyComponentsRoutingLoaderXmlFileLoader; $loader = new XmlFileLoader(); $routes = $loader->load('routes.xml'); The Symfony Components – Fabien Potencier
  • 111. <?xml version="1.0" encoding="UTF-8" ?> <routes> <route id="home" pattern="/"> <default key="controller">home</default> <default key="action">index</default> </route> <import resource="blog.yml" prefix="/blog" /> <import resource="forum.xml" prefix="/forum" /> </routes> The Symfony Components – Fabien Potencier
  • 112. home: pattern: / defaults: { controller: home, action: index } import: - { resource: blog.yml, prefix: /blog } - { resource: forum.xml, prefix: /forum } The Symfony Components – Fabien Potencier
  • 113. $yamlLoader = new YamlFileLoader(); $xmlLoader = new XmlFileLoader(); $routes = new RouteCollection(); $route = new Route( '/', array('to' => function () { echo "Home!"; }) ); $routes->addRoute('home', $route); $routes->addCollection( $yamlLoader->load('blog.yml'), '/blog'); $routes->addCollection( $xmlLoader->load('forum.xml'), '/forum'); The Symfony Components – Fabien Potencier
  • 114. /blog/2010/03/10/confoo prefix pattern The Symfony Components – Fabien Potencier
  • 115. Routing Make it simple & fast The Symfony Components – Fabien Potencier
  • 116. use SymfonyComponentsRoutingRouter; $router = new Router($loader, $options, $context); The Symfony Components – Fabien Potencier
  • 117. $loader = function () { $routes = new RouteCollection(); // ... return $routes; }; $context = array( 'base_url' => '/myapp', 'host' => 'www.example.com', 'is_secure' => false, ); $options = array( 'cache_dir' => '/tmp/routing', 'debug' => true, ); The Symfony Components – Fabien Potencier
  • 118. $router = new Router($loader, $options, $context); if (false === $params = $router->match('/')) { throw new Exception('No route matches.'); } echo $router->generate('home', array()); The Symfony Components – Fabien Potencier
  • 119. class ProjectUrlMatcher extends SymfonyComponentsRouting MatcherUrlMatcher { // ... public function match($url) { $url = $this->normalizeUrl($url); if (preg_match('#^/$#x', $url, $matches)) return array_merge($this->mergeDefaults($matches, array ( 'to' => 'foo',)), array('_route' => 'home')); return false; } } The Symfony Components – Fabien Potencier
  • 120. class ProjectUrlGenerator extends SymfonyComponentsRoutingGeneratorUrlGenerator { // ... public function generate($name, array $parameters, $absolute = false) { if (!method_exists($this, $method = 'get'.$name.'RouteInfo')) { throw new InvalidArgumentException(sprintf('Route "%s" does not exist.', $name)); } list($variables, $defaults, $requirements, $tokens) = $this->$method(); return $this->doGenerate($variables, $defaults, $requirements, $tokens, $parameters, $name, $absolute); } protected function gethomeRouteInfo() { return array(array (), array_merge($this->defaults, array ( 'to' => 'foo',)), array (), array ( 0 => array ( 0 => 'text', 1 => '/', 2 => '', 3 => NULL, ),)); } } The Symfony Components – Fabien Potencier
  • 121. use SymfonyComponentsRoutingFileResource; $loader = function () { $routes = new RouteCollection(); // ... $routes->addResource(new FileResource(__FILE__)); return $routes; }; The Symfony Components – Fabien Potencier
  • 122. Routing Make it really fast The Symfony Components – Fabien Potencier
  • 123. use SymfonyComponentsRoutingMatcherDumper ApacheMatcherDumper; $dumper = new ApacheMatcherDumper($routes); echo $dumper->dump(); The Symfony Components – Fabien Potencier
  • 124. RewriteCond %{PATH_INFO} ^/$ RewriteRule .* index.php [QSA,L,E=_ROUTING__route:home,E=_ROUTING_to:foo ] The Symfony Components – Fabien Potencier
  • 125. $options = array( 'cache_dir' => '/tmp/routing', 'debug' => true, 'matcher_class' => 'SymfonyComponents RoutingMatcherApacheUrlMatcher', ); The Symfony Components – Fabien Potencier
  • 126. Output Escaper The Symfony Components – Fabien Potencier
  • 127. Provides XSS protection for your PHP templates The Symfony Components – Fabien Potencier
  • 128. Wraps template variables Works for strings arrays objects properties methods __call(), __get(), … Iterators, Coutables, … … Works for deep method calls The Symfony Components – Fabien Potencier
  • 129. use SymfonyComponentsOutputEscaperEscaper; $title = 'Foo <br />'; echo Escaper::escape('htmlspecialchars', $title); The Symfony Components – Fabien Potencier
  • 130. use SymfonyComponentsOutputEscaperEscaper; $article = array( 'title' => 'Foo <br />', 'author' => array( 'name' => 'Fabien <br/>', ) ); $article = Escaper::escape('htmlspecialchars', $article); echo $article['title']."n"; echo $article['author']['name']."n"; The Symfony Components – Fabien Potencier
  • 131. class Article { protected $title; protected $author; public $full_title; public property public function __construct($title, Author $author) { $this->title = $title; $this->full_title = $title; $this->author = $author; } public method public function getTitle() { return $this->title; } public function getAuthor() { return $this->author; } public method returning public function __get($key) { return $this->$key; } another object public function __call($method, $arguments) { magic __get() return $this->{'get'.$method}(); magic __call() } } The Symfony Components – Fabien Potencier
  • 132. class Author { protected $name; public function __construct($name) { $this->name = $name; } public function getName() { return $this->name; } } The Symfony Components – Fabien Potencier
  • 133. use SymfonyComponentsOutputEscaperEscaper; $article = new Article( 'foo <br />', new Author('Fabien <br />') ); $article = Escaper::escape('htmlspecialchars', $article); echo $article->getTitle()."n"; echo $article->getAuthor()->getName()."n"; echo $article->full_title."n"; echo $article->title."n"; echo $article->title()."n"; The Symfony Components – Fabien Potencier
  • 134. explicitly ask for raw data echo $article->getHtmlContent('raw'); echo $article->getTitle('js'); change the default escaping strategy The Symfony Components – Fabien Potencier
  • 135. Request Handler The Symfony Components – Fabien Potencier
  • 136. use SymfonyComponentsRequestHandlerRequest; $request = new Request(); $request->getPathInfo(); $request->getPreferredLanguage(array('en', 'fr')); $request->isXmlHttpRequest(); The Symfony Components – Fabien Potencier
  • 137. use SymfonyComponentsRequestHandlerRequest; $request = new Request(array( 'request' => $_POST, 'query' => $_GET, 'path' => array(), 'server' => $_SERVER, )); The Symfony Components – Fabien Potencier
  • 138. use SymfonyComponentsRequestHandlerResponse; $response = new Response('Hello World', 200, array('Content-Type' => 'text/plain')); $response->send(); $response->setHeader('Content-Type', 'text/plain'); $response->setCookie('foo', 'bar'); $response->setContent('Hello World'); $response->setStatusCode(200); The Symfony Components – Fabien Potencier
  • 139. Request Handler Framework to build Frameworks The Symfony Components – Fabien Potencier
  • 140. use SymfonyComponentsRequestHandlerRequest; use SymfonyComponentsRequestHandlerResponse; use SymfonyComponentsRequestHandlerRequestHandler; $handler = new RequestHandler($dispatcher); $request = new Request(); $response = $handler->handle($request); $response->send(); The Symfony Components – Fabien Potencier
  • 141. use SymfonyComponentsEventDispatcherEventDispatcher; use SymfonyComponentsEventDispatcherEvent; $dispatcher = new EventDispatcher(); $dispatcher->connect('core.load_controller', function (Event $event) { $event->setReturnValue(array( function ($request) { return new Response('Hello!'); }, array($event['request']) )); return true; }); The Symfony Components – Fabien Potencier
  • 142. Request Handler A small Framework The Symfony Components – Fabien Potencier
  • 143. $framework = new Framework(array( '/' => function ($request) { $content = 'Hello '. $request->getParameter('name'); return new Response($content); } )); $framework->run(); The Symfony Components – Fabien Potencier
  • 144. class Framework { protected $map; public function __construct($map) { $this->map = $map; } public function run() { $dispatcher = new EventDispatcher(); $dispatcher->connect('core.load_controller', array($this, 'loadController')); $handler = new RequestHandler($dispatcher); $response = $handler->handle(new Request()); $response->send(); } } The Symfony Components – Fabien Potencier
  • 145. public function loadController(Event $event) { $request = $event['request']; $routes = new RouteCollection(); foreach ($this->map as $pattern => $to) { $route = new Route($pattern, array('to' => $to)); $routes->addRoute(str_replace('/', '_', $pattern), $route); } $matcher = new UrlMatcher($routes, array( 'base_url' => $request->getBaseUrl(), 'method' => $request->getMethod(), 'host' => $request->getHost(), 'is_secure' => $request->isSecure(), )); $parameters = $matcher->match($request->getPathInfo()); if (false === $parameters) { return false; } $request->setPathParameters($parameters); $event->setReturnValue(array($parameters['to'], array($request))); return true; } The Symfony Components – Fabien Potencier
  • 146. $framework = new Framework(array( '/' => function ($request) { $content = 'Hello '. $request->getParameter('name'); return new Response($content); } )); $framework->run(); The Symfony Components – Fabien Potencier
  • 147. Questions? The Symfony Components – Fabien Potencier
  • 148. Sensio S.A. 92-98, boulevard Victor Hugo 92 115 Clichy Cedex FRANCE Tél. : +33 1 40 99 80 80 Contact Fabien Potencier fabien.potencier at sensio.com http://www.sensiolabs.com/ http://www.symfony-project.org/ http://fabien.potencier.org/ The Symfony Components – Fabien Potencier